package agency.tango.materialintroscreen.widgets;

import agency.tango.materialintroscreen.ResourceTable;
import agency.tango.materialintroscreen.adapter.SlidesAdapter;
import agency.tango.materialintroscreen.interceptor.AccelerateInterpolator;
import agency.tango.materialintroscreen.interceptor.Interpolator;
import agency.tango.materialintroscreen.listeners.GiveTouchToParentListener;
import agency.tango.materialintroscreen.listeners.IFinishListener;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.PageSlider;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.multimodalinput.event.TouchEvent;

/**
 * @ProjectName: material-intro-screen-master
 * @Package: agency.tango.materialintroscreen.widgets
 * @ClassName: OverScrollViewPager
 * @Description: 封装pageslider 在滑动时回调结束松手之后
 * 如果页面没有将页面居中负责归位页面或者滑到下一页
 * 如果滑动的是最后一页需要关闭展示页面
 * @CreateDate: 2021/4/12 18:13
 * @UpdateDate: 2021/4/12 18:13
 * @UpdateRemark: 暂无
 * @Version: 1.0
 */

public class OverScrollViewPager extends DependentLayout implements Component.TouchEventListener
        , GiveTouchToParentListener {
    private SwipeableViewPager swipeableViewPager = null;
    private float mMotionBeginX = 0;
    private float positionOffset = 0;
    private IFinishListener finishListener;
    private float moveOffset;


    public OverScrollViewPager(Context context) {
        this(context, null);
    }


    public OverScrollViewPager(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    /**
     * 构造器 初始化pageslider
     *
     * @param context   上下文
     * @param attrSet   属性集
     * @param styleName 样式名称
     */
    public OverScrollViewPager(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        swipeableViewPager = createOverScrollView();
        LayoutConfig layoutParams = new LayoutConfig(
                LayoutConfig.MATCH_PARENT,
                LayoutConfig.MATCH_PARENT);
        swipeableViewPager.setTouchToParentListener(this);
        addComponent(swipeableViewPager, layoutParams);
        initView();
    }

    private void initView() {
        setTouchEventListener(this);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        return true;
    }

    @Override
    public void onTouchDown(Component component, TouchEvent event) {
        mMotionBeginX = event.getPointerScreenPosition(0).getX();
    }

    @Override
    public void onTouchMove(Component component, TouchEvent event) {
        moveOffset = event.getPointerScreenPosition(0).getX() - mMotionBeginX;
        positionOffset = calculateOffset(moveOffset);
        if (moveOffset < 0) {
            setTranslationX(moveOffset);
            setAlpha(1 - positionOffset);
            requestChildSliding();
        }
    }

    @Override
    public void onTouchUp(Component component, TouchEvent event) {
        moveOffset = event.getPointerScreenPosition(0).getX() - mMotionBeginX;
        if (positionOffset > 0.5f) {
            finishOverScrollViewWithAnimation(moveOffset);
        } else {
            resetOverScrollViewWithAnimation(moveOffset);
        }
    }

    @Override
    public void onTransToOrigin(Component component, TouchEvent event) {
        setTranslationX(0);
        setAlpha(1);
    }

    /**
     * 获取滑动控件
     *
     * @return SwipeableViewPager
     */
    public SwipeableViewPager getOverScrollView() {
        return swipeableViewPager;
    }

    /**
     * 注册页面结束关闭监听器
     *
     * @param listener 页面结束关闭监听器
     */
    public void registerFinishListener(IFinishListener listener) {
        finishListener = listener;
    }

    /**
     * pageslider滑动的时候如果需要则同步滑动本容器
     *
     * @param currentX 移动偏移量
     * @return 是否可以滑动
     */
    private boolean moveOverScrollView(float currentX) {
        if (canScroll(currentX)) {
            scrollTo((int) -currentX, 0);
            positionOffset = calculateOffset(currentX);
            requestChildSliding();
            if (shouldFinish()) {
                finishListener.doOnFinish();
            }
            return true;
        }
        return false;
    }

    /**
     * 将容器的TranslationX回归到初始值
     * 以及alpha同步回归到初始值1
     *
     * @param transX 移动偏移量
     * @return 是否可以滑动
     */
    private void transOverScrollView(float transX, float alpha) {
        setTranslationX(transX);
        if (0 <= alpha && alpha <= 1) {
            setAlpha(alpha);
        } else {
            setAlpha(alpha);
        }
    }

    private void requestChildSliding() {
        if (swipeableViewPager != null && swipeableViewPager.getOnPageChangeListeners() != null) {
            for (int i = 0; i < swipeableViewPager.getOnPageChangeListeners().size(); i++) {
                PageSlider.PageChangedListener pageChangedListener =
                        swipeableViewPager.getOnPageChangeListeners().get(i);
                if (pageChangedListener != null) {
                    pageChangedListener.onPageSliding(swipeableViewPager.getAdapter().getLastItemPosition(), positionOffset, 0);
                }
            }
        }

    }

    /**
     * 计算本容器的偏移量
     *
     * @return 本容器的偏移量
     */
    private float calculateOffset(float moveOffset) {
        float width = (float) getWidth();
        return Math.abs(moveOffset) / width;
    }

    /**
     * 判断本容器的滑动是否结束
     *
     * @return 本容器的滑动是否结束
     */
    private boolean shouldFinish() {
        return positionOffset == 1f;
    }

    /**
     * 判断本容器是否可以滑动
     *
     * @param currentX 本容器滑动偏移量
     * @return 本容器是否可以滑动
     */
    private boolean canScroll(float currentX) {
        return currentX <= 0f;
    }

    /**
     * 随着动画重置本容器状态
     *
     * @param currentX 本容器偏移量
     */
    private void resetOverScrollViewWithAnimation(final float currentX) {
        EventHandler current =
                new EventHandler(EventRunner.getMainEventRunner());
        SmoothScrollRunnable task = new SmoothScrollRunnable((int) currentX, 0, 300,
                new AccelerateInterpolator());
        task.setFinish(false);
        task.setStartTransX(getTranslationX(), 0, getAlpha(), 1);
        current.postTask(task);
    }

    /**
     * 随着动画关闭本容器页面
     *
     * @param currentX 本容器偏移量
     */
    private void finishOverScrollViewWithAnimation(float currentX) {
        EventHandler current =
                new EventHandler(EventRunner.getMainEventRunner());
        SmoothScrollRunnable task = new SmoothScrollRunnable((int) currentX, -getWidth(), 300,
                new AccelerateInterpolator());
        task.setFinish(true);
        current.postTask(task);
    }

    /**
     * 判断在pageslider最后一页是否可以滑动
     *
     * @return 是否可以滑动
     */
    private boolean canOverScrollAtEnd() {
        SwipeableViewPager viewPager = getOverScrollView();
        SlidesAdapter adapter = viewPager.getAdapter();
        if (adapter != null && adapter.getCount() > 0) {
            if (viewPager.alphaExitTransitionEnabled() && viewPager.getCurrentPage() == adapter.getCount() - 1) {
                return true;
            }
            return false;
        }

        return false;
    }

    /**
     * 初始化生成pageslider
     *
     * @return pageslider
     */
    private SwipeableViewPager createOverScrollView() {
        SwipeableViewPager viewPager =
                new SwipeableViewPager(getContext(), null);
        viewPager.setId(ResourceTable.String_swipeable_view_pager);
        return viewPager;
    }

    final class SmoothScrollRunnable implements Runnable {
        private final Interpolator interpolator;
        private final int scrollToPosition;
        private final int scrollFromPosition;
        private final long duration;

        private long startTime = -1;
        private int currentPosition = -1;

        private float startTransX = -1;
        private float endTransX = -1;
        private float startAlpha = -1;
        private float endAlpha = -1;
        private boolean isFinish = false;

        SmoothScrollRunnable(int fromPosition, int toPosition, long duration,
                             Interpolator interpolator) {
            scrollFromPosition = fromPosition;
            scrollToPosition = toPosition;
            this.interpolator = interpolator;
            this.duration = duration;
        }

        /**
         * 设置是否需要关闭页面
         *
         * @param finish 是否需要关闭页面
         */
        public void setFinish(boolean finish) {
            isFinish = finish;
        }

        /**
         * 设置回弹的时候TranslationX的初始值 最终值
         * alpha的初始值 最终值，用于将父容器回弹
         *
         * @param startTransX TranslationX的初始值
         * @param endTransX   TranslationX的最终值
         * @param startAlpha  alpha的初始值
         * @param endAlpha    alpha的最终值
         */
        public void setStartTransX(float startTransX, float endTransX, float startAlpha, float endAlpha) {
            this.startTransX = startTransX;
            this.endTransX = endTransX;
            this.startAlpha = startAlpha;
            this.endAlpha = endAlpha;
        }

        @Override
        public void run() {
            if (startTime == -1) {
                startTime = System.currentTimeMillis();
            } else {
                long normalizedTime =
                        (1000 * (System.currentTimeMillis() - startTime)) / duration;
                normalizedTime = Math.max(Math.min(normalizedTime, 1000), 0);
                if (!isFinish) {
                    final float delTranX = (endTransX - startTransX) * interpolator.getInterpolation(normalizedTime / 1000f) + startTransX;
                    final float dealAlpha = (endAlpha - startAlpha) * interpolator.getInterpolation(normalizedTime / 1000f) + startAlpha;
                    transOverScrollView(delTranX, dealAlpha);
                }
                final int deltaY =
                        Math.round((scrollFromPosition - scrollToPosition)
                                * interpolator.getInterpolation(normalizedTime / 1000f));
                currentPosition = scrollFromPosition - deltaY;
                moveOverScrollView(currentPosition);
            }

            if (scrollToPosition != currentPosition) {
                new EventHandler(EventRunner.getMainEventRunner()).postTask(this);
            }
        }
    }
}